package itsm.isperp.framework.security.access.intercept;

import itsm.isperp.framework.security.domain.UrlDefinition;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.DelegatingFilterProxy;

/**
 * 扩展自Spring Security DelegatingFilterProxy类，用于在进行权限判断之前过滤掉那些不需要进行权限判断的URL
 */
public class SecurityFilterProxy extends DelegatingFilterProxy {
	private List<UrlDefinition> urlList = new ArrayList<UrlDefinition>();;
	private PathMatcher urlMatcher = new AntPathMatcher();
	private SecurityContextRepository repo = new HttpSessionSecurityContextRepository();
	protected final Log logger = LogFactory.getLog(getClass());

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws ServletException, IOException {
		String url = buildRequestUrl((HttpServletRequest) request);
		logger.debug("request url is :" + url);
		url = parseUrl(url, false);
		if (url.startsWith("/")) {
			url = url.substring(1, url.length());
		}
		if (url.indexOf("?") != -1) {
			url = url.substring(0, url.indexOf("?"));
		}
		boolean doFilter = true;
		for (UrlDefinition definition : urlList) {
			if (urlMatcher.match(definition.getUrl(), url)) {
				doFilter = false;
				break;
			}
		}

		if (doFilter) {
			super.doFilter(request, response, filterChain);
		} else {
			HttpRequestResponseHolder holder = new HttpRequestResponseHolder(
					(HttpServletRequest) request,
					(HttpServletResponse) response);
			SecurityContext contextBeforeChainExecution = repo
					.loadContext(holder);
			SecurityContextHolder.setContext(contextBeforeChainExecution);
			try {
				filterChain.doFilter(request, response);
			} finally {
				SecurityContextHolder.clearContext();
			}
		}
	}

	private String buildRequestUrl(HttpServletRequest request) {
		String servletPath = request.getServletPath();
		String requestURI = request.getRequestURI();
		String contextPath = request.getContextPath();
		String pathInfo = request.getPathInfo();
		StringBuilder url = new StringBuilder();

		if (servletPath != null) {
			url.append(servletPath);
			if (pathInfo != null) {
				url.append(pathInfo);
			}
		} else {
			url.append(requestURI.substring(contextPath.length()));
		}
		return url.toString();
	}

	@Override
	protected void initFilterBean() throws ServletException {
		super.initFilterBean();

	}

	private String parseUrl(String url, boolean force) {
		if (force || url.endsWith(".d") || url.endsWith(".c")) {
			int p = url.lastIndexOf(".");
			if (p > -1) {
				String tmp = url.substring(p, url.length());
				url = url.substring(0, url.lastIndexOf("."));
				url = url.replace(".", "/");
				url = url + tmp;
			}
		}
		return url;
	}

}
